#include <QtGui>
#include <QtOpenGL>

#include "GlWindow.h"
#include "Board.h"

GlWindow::GlWindow(QWidget *parent)
	: QGLWidget(parent)
{
	clearColor = Qt::black;

	setAnimated( false );
	setMoveAsked(false);
	angle = 180;
	board = NULL;
	animationSetting = true;
	regularMovesSetting = true;
	lastMoveSetting = true;

//	setAnimationSetting( true );
//	setRegularMovesSetting( true );
//	setLastMoveSetting( true );
	
	timer = new QTimer(this);
	connect(timer, SIGNAL( timeout() ), this, SLOT( updateScene() ) );
}

GlWindow::~GlWindow()
{
}

//Taille minimum de redimenssionnement
QSize GlWindow::minimumSizeHint() const
{
	return QSize(600,600);
}

//Taille au démarrage
QSize GlWindow::sizeHint() const
{
	return QSize(500,500);
}




void GlWindow::updateGL()
{
}

void GlWindow::updateScene()
{
//	cout << "\tEntre ds \"GlWindow::updateScene()\"" << endl;	

	if( animationSetting == false )
	{
		board->clearAnimation();
	}
	
	if( board->getAnimated() && getAnimated()==false )  //Si le board contient des animations et qu'elles ne sont pas commencées
	{
		timer->start( 10 );
		setAnimated( true );
	}


	if( getAnimated() )  //Si la scène est en animation
	{
	angle -= AngleSpeedAnimation;  //MAJ de l'angle de rotation de l'animation
		if( angle <= 0 )  //Animation terminée
		{
			angle = 180;
			setAnimated( false );
			board->clearAnimation();
			timer->stop();
			emit animationDone();
		}
	}

	repaint();  //Redessine le Widget

//Si AnimationSetting désactivé, animationDone() après un seul affichage.
	if( animationSetting == false )
	{
		emit animationDone();
	}
}


//Initialisation de la machine OpenGl
void GlWindow::initializeGL()
{			
    //Définition de la couleur de fond
	qglClearColor(clearColor);
	
	//Activation Z-buffer
	glEnable(GL_DEPTH_TEST);
	
//	gluQuadricDrawStyle(quadric, GLU_FILL);  //mode de dessin "plein":GLU_FILL,   filaire:GLU_LINE

	//Chargement des textures
	loadTextures();

	//Création du plateau
	boardLayout = makeBoard();
}

void GlWindow::resizeGL(int width, int height)
{
	//Définition du Viewport
    int side = qMin(width, height);
    glViewport((width - side) / 2, (height - side) / 2, side, side);
//	glViewport(0,0,width,height);
//	resize(side,side);
	
	//Définition de la matrice de projection
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 100.0, 100.0, 0.0, 0, 100.0);  //Vue orthogonale
    glMatrixMode(GL_MODELVIEW);
}

void GlWindow::paintGL()
{	
	//Remplissage de la fenêtre par la couleur de fond
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //Effacement du tampon d'image (COLOR_BUFFER) et du tampon de profondeur (DEPTH_BUFFER)
	
    glLoadIdentity();
//---------------Caméra-------------------------------------------
	glTranslatef(0.0,0.0,-50.0);
	
//--------------Dessin Plateau----------------------------------	
	glCallList(boardLayout);
	
//--------------Dessin pions--------------------------------
	drawPawnsLayout();
}

//Dessine un pion à l'écran
//Coté Noir visible
void GlWindow::pawnDrawing(GLUquadricObj *quadric)
{
	glPushMatrix();  //sauvegarde de la matrice
	qglColor(Qt::black);
	gluCylinder(quadric,4.5,4.5,1,20,20);
	glTranslatef(0.0,0.0,1.0f);
	gluDisk(quadric,0,4.5,20,20);
	glPopMatrix();
	qglColor(Qt::white);
	glTranslatef(0.0,0.0,-1.0);
	gluCylinder(quadric,4.5,4.5,1,20,20);
	gluDisk(quadric,0,4.5,20,20);
	glPopMatrix();
}

void GlWindow::regularMoveDrawing(GLUquadricObj *quadric)
{
	qglColor(Qt::lightGray);
	gluDisk(quadric,0,1.0,20,20);
	glPopMatrix();
}

void GlWindow::lastMoveDrawing(GLUquadricObj *quadric)
{
	glTranslatef(0.0,0.0,2.0);
	qglColor(Qt::darkRed);
	gluDisk(quadric,0,1.0,20,20);
	glPopMatrix();
}

//Afiche l'ensemble des pions à l'écran
void GlWindow::drawPawnsLayout()
{	
	GLUquadricObj *quadric = gluNewQuadric();  //création d un quadrique
	gluQuadricDrawStyle(quadric, GLU_FILL);  //mode de dessin "plein":GLU_FILL,   filaire:GLU_LINE
	
	//Parcours de la board
	for( int y=0 ; y<8 ; y++ ){
		for( int x=0 ; x<8 ; x++ ){
			
			switch( board->getTypeSquareBoard(x,y) )
			{
				case Occupied:  //Case occupé par un pion
					glPushMatrix();
					glTranslatef(WidthBorderText + x*WidthSquareText + WidthRadiusPawn, WidthBorderText + y*WidthSquareText + WidthRadiusPawn, 5.0f);
					if( board->getColorPawnBoard(x,y) == White )  //Si c est un pion blanc, il faut le retourner
					{
						glRotatef(180,0.0f,1.0f,0.0f);
					}
					if( board->getAnimatedSquare(x, y) )
					{  //Si le pion est en animation
						glRotatef(angle,0.0f,1.0f,0.0f);  //Rotation du pion pour l'animation
					}
					pawnDrawing(quadric);
					if( getLastMoveSetting() && board->getLastMoveSquare(x,y) )
					{  //Si la case est la dernière jouée
						//Affichage du dernier coup
						glPushMatrix();
						glTranslatef(WidthBorderText + x*WidthSquareText + WidthRadiusPawn, WidthBorderText + y*WidthSquareText + WidthRadiusPawn, 5.0f);
						lastMoveDrawing(quadric);
					}
					break;
				case RegularMove:  //Coup légal
					if( getRegularMovesSetting() )
					{
						glPushMatrix();
						glTranslatef(WidthBorderText + x*WidthSquareText + WidthRadiusPawn, WidthBorderText + y*WidthSquareText + WidthRadiusPawn, 5.0f);
						regularMoveDrawing(quadric);						
					}
					break;
				case Empty:  //Case vide
					break;
				default:  //Cas impossible si pas de bugs...
					break;
			}
		}
	}
	gluDeleteQuadric(quadric);
}


void GlWindow::mousePressEvent( QMouseEvent *event )
{
}

void GlWindow::mouseReleaseEvent( QMouseEvent * event )
{
//	unsetCursor();
//	setCursor(Qt::ArrowCursor);
//	setCursor(Qt::PointingHandCursor);
	
//	cout << "Entre ds \"GlWindow::mouseReleaseEvent()\"" << endl;

	if( getMoveAsked() )  //Si un coup est demandé par le moteur de jeu
	{
		int squareX, squareY,
			clicX = event->x(), clicY = event->y(),
			widthWidget = width(), heightWidget = height();
		
		//Calcul de la largeur du plateau ( = min(widthWidget,heightWidget) )
		int widthBoard = widthWidget;
		if( heightWidget < widthWidget )
		{
			widthBoard = heightWidget;
		}
		//Largeur de ma bordure ds le widget affiché en pixel
		int widthBorder = widthBoard / ( 2.0 + (8.0 * WidthSquareText / WidthBorderText) );
		//Largeur d une case ds le widget affiché en pixel
		int widthSquare = (widthBoard - (2*widthBorder)) / 8.0;
		
		//Plus large que haut
		if( widthWidget > heightWidget )
		{			
			squareX = ( clicX - ( (widthWidget-heightWidget)/2.0 ) - widthBorder ) / ( widthSquare );
			squareY = ( clicY - widthBorder ) / ( widthSquare );
		}
		
		//Plus haut que large
		else if( widthWidget < heightWidget )
		{
			squareX = ( clicX - widthBorder ) / ( widthSquare );
			squareY = ( clicY - ((heightWidget-widthWidget)/2.0) - widthBorder ) / (widthSquare);
		}
		//Largeur=Hauteur
		else
		{
			squareX = ( clicX - widthBorder ) / widthSquare;
			squareY = ( clicY - widthBorder ) / widthSquare;
		}
		
//		squareX--;
//		squareY--;
		
		if( squareX >= 0 && squareY >= 0 && squareX<8 && squareY<8 )
		{
			setMoveAsked(false);  //Demande du coup réalisé dc askingMove=false
//			cout << "Emission de \"GlWindow::boardHasClicked(int,int)\"" << endl;
			emit boardHasClicked(squareX,squareY);
		}
	}
}


GLuint GlWindow::makeBoard()
{
	GLuint list = glGenLists(1);
    glNewList(list, GL_COMPILE);
	
	//Activation du texturage 2D
	glEnable(GL_TEXTURE_2D);

		//Sélection de la couleur "blanc" pour ne pas interférer le texturage
		qglColor(Qt::white);
	
		//Sélection de la texture à appliquer
		glBindTexture(GL_TEXTURE_2D, textures[0]);

		//Dessin du plateau
		glBegin(GL_QUADS);
			glTexCoord2d(0,1);  glVertex3f( 0.0f,0.0f, 0.0f);
			glTexCoord2d(0,0);  glVertex3f( 0.0f, 100.0f, 0.0f);
			glTexCoord2d(1,0);  glVertex3f( 100.0f, 100.0f, 0.0f);
			glTexCoord2d(1,1);  glVertex3f( 100.0f,0.0f, 0.0f);
		glEnd();
	
		//Désactivation du texturage 2D
		glDisable(GL_TEXTURE_2D);
	
	glEndList();
	
	return list;
}

void GlWindow::loadTextures()
{
	QImage t, b;
	
	b.load( ":/images/Board.bmp" );
	t = QGLWidget::convertToGLFormat( b );
	glGenTextures( 1, &textures[0] );
	glBindTexture( GL_TEXTURE_2D, textures[0] );
	glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
	
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}


void GlWindow::setAnimationSetting( bool b)
{
	animationSetting = b;
}

bool GlWindow::getAnimationSetting()
{
	return animationSetting;
}

void GlWindow::setRegularMovesSetting( bool b)
{
	regularMovesSetting = b;
	updateScene();
}

bool GlWindow::getRegularMovesSetting()
{
	return regularMovesSetting;
}

void GlWindow::setLastMoveSetting( bool b)
{
	lastMoveSetting = b;
	updateScene();
}

bool GlWindow::getLastMoveSetting()
{
	return lastMoveSetting;
}

void GlWindow::setAnimated( bool b)
{
	animated =b;
}

bool GlWindow::getAnimated()
{
	return animated;
}

void GlWindow::setMoveAsked(bool b)
{
//	cout << "Entre ds \"GlWindow::setMoveAsked(" << b << ")\"" << endl;
	moveAsked = b;
//	cout << "\tGlWindow::moveAsked = " << moveAsked << endl;
}

bool GlWindow::getMoveAsked()
{
//	cout << "Entre ds \"GlWindow::getMoveAsked()\"" << endl;
//	cout << "\tGlWindow::moveAsked = " << moveAsked << endl;
	return moveAsked;
}

void GlWindow::askingMoveReceived()
{
//	cout << "Entre ds \"GlWindow::askingMoveReceived()\"" << endl;
	setMoveAsked(true);
}

void GlWindow::setBoard(Board *b)
{
	board = b;
}

void GlWindow::connecting( GameEngine *ge )
{
	connect( this, SIGNAL( boardHasClicked(int,int) ), ge, SLOT( recupMove(int,int) ) );
	connect( ge, SIGNAL( askingLocalMove() ), this, SLOT( askingMoveReceived() ) );
	connect( this, SIGNAL( animationDone() ), ge, SLOT( nextTurn() ) );
	connect( ge, SIGNAL( boardModified() ), this, SLOT( updateScene() ) );

	setBoard( ge->getBoard() );
}
